//
//  YSSqliteTool.m
//  YSSqliteTool_Example
//
//  Created by Kyson on 2018/12/4.
//  Copyright © 2018 kysonyangs. All rights reserved.
//

#import "YSSqliteTool.h"
#import "sqlite3.h"

#define kCachePath NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject

@implementation YSSqliteTool

sqlite3 *ppDb = nil;

+ (BOOL)deal:(NSString *)sql uid:(NSString *)uid {
    
    if (![self openDB:uid]) {
        NSLog(@"打开数据库失败");
        return NO;
    }
    
    BOOL result = sqlite3_exec(ppDb, sql.UTF8String, nil, nil, nil) == SQLITE_OK;
    
    [self closeDB];
    
    return result;
}

+ (BOOL)dealSqls:(NSArray<NSString *> *)sqls uid:(NSString *)uid {
    
    [self beginTransaction:uid];
    
    for (NSString *sql in sqls) {
        if (![self deal:sql uid:uid]) {
            [self rollBackTransaction:uid];
            return NO;
        }
    }
    
    [self commitTransaction:uid];
    return YES;
}

+ (NSMutableArray<NSMutableDictionary *> *)querySql:(NSString *)sql uid:(NSString *)uid {
    // 预处理语句
    if (![self openDB:uid]) {
        NSLog(@"打开数据库失败");
        return nil;
    }
    
    // 1. 准备预处理数据
    // 参数3: 参数2取出字节长度 -1 自动计算 \0
    // 参数4: 准备语句
    // 参数5: 通过参数3，取出参数2的长度字节之后，剩下的字符串
    sqlite3_stmt *ppStmt = nil;
    if (sqlite3_prepare_v2(ppDb, sql.UTF8String, -1, &ppStmt, nil) != SQLITE_OK) {
        NSLog(@"准备语句编译失败");
        return nil;
    }
    
    // 2. 绑定数据
    NSMutableArray *rowDicArray = [NSMutableArray array];
    // 3. 执行
    while (sqlite3_step(ppStmt) == SQLITE_ROW) {
        NSMutableDictionary *rowDic = [NSMutableDictionary dictionary];
        [rowDicArray addObject:rowDic];
        // 一行记录 -> 字典
        int columnCount = sqlite3_column_count(ppStmt);
        
        for (int i = 0; i < columnCount; i++) {
            // 1. 获取列名
            const char *name = sqlite3_column_name(ppStmt, i);
            NSString *columnName = [NSString stringWithUTF8String:name];
            
            // 2. 获取列值
            // 2.1 获取列的类型
            int type = sqlite3_column_type(ppStmt, i);
            
            // 2.2 获取列的值
            id value = nil;
            switch (type) {
                case SQLITE_INTEGER:
                    value = @(sqlite3_column_int(ppStmt, i));
                    break;
                case SQLITE_FLOAT:
                    value = @(sqlite3_column_double(ppStmt, i));
                    break;
                case SQLITE_BLOB:
                    value = CFBridgingRelease(sqlite3_column_blob(ppStmt, i));
                    break;
                case SQLITE_NULL:
                    value = @"";
                    break;
                case SQLITE3_TEXT:
                    value = [NSString stringWithUTF8String:(const char *)sqlite3_column_text(ppStmt, i)];
                    break;
                default:
                    break;
            }
            
            [rowDic setValue:value forKey:columnName];
        }
    }
    
    // 4.重置
    
    // 5. 释放资源
    [self closeDB];
    
    return rowDicArray;
}

+ (void)beginTransaction:(NSString *)uid {
    [self deal:@"begin transaction" uid:uid];
}

+ (void)commitTransaction:(NSString *)uid {
    [self deal:@"commit transaction" uid:uid];
}

+ (void)rollBackTransaction:(NSString *)uid {
    [self deal:@"rollback transaction" uid:uid];
}

#pragma mark - private method
+ (BOOL)openDB:(NSString *)uid {
    NSString *dbName = [NSString stringWithFormat:@"%@.sqlite", uid ?: @"common"];
    NSString *dbPath = [kCachePath stringByAppendingPathComponent:dbName];        
    return sqlite3_open(dbPath.UTF8String, &ppDb) == SQLITE_OK;
}

+ (void)closeDB {
    sqlite3_close(ppDb);
}

@end
